/* Declarations for the byte vector type.

   This file is part of khipu.

   khipu is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */

#ifndef __KP_BVECTOR__
#define __KP_BVECTOR__   1

#include "interp.hpp"
#include "initop.hpp"

KP_DECLS_BEGIN

struct bvector : public varobj
{
  static const int code = typecode::BVECTOR;

  unsigned char *data;
  uint32_t nbytes;

  static bvector* alloc_raw (uint32_t cap);

  // Needed by the raw_acc interface.
  uint32_t& len_ref ()
    {
      return (this->nbytes);
    }

  unsigned char* data_ptr ()
    {
      return (this->data);
    }

  void local_init (const void *ptr, uint32_t nbytes)
    {
      this->data = (unsigned char *)ptr;
      this->nbytes = nbytes;
    }
};

inline bvector* as_bvector (object obj)
{
  return ((bvector *)unmask (obj));
}

#ifdef KP_ARCH_WIDE

inline constexpr bool bvector_p (object obj)
{
  return (itype (obj) == typecode::BVECTOR);
}

#else

inline bool bvector_p (object obj)
{
  return (varobj_p (obj) && as_varobj(obj)->vo_type == typecode::BVECTOR);
}

#endif

inline uint32_t
len_b (object obj)
{
  return (as_bvector(obj)->nbytes);
}

/* Byte vectors and strings share a large part of the implementation,
 * since the latter can be considered a subtype of the former. */

struct stream;
struct io_info;
struct pack_info;

// Allocate a byte vector with room for NBYTES bytes.
KP_EXPORT result<object> alloc_bvector (interpreter *interp, uint32_t nbytes);

// Index a byte vector.
KP_EXPORT result<object> get_b (interpreter *interp,
                                object bvector, object idx, object dfl);

// Get the subsequence of a byte vector.
KP_EXPORT result<object> subseq_b (interpreter *interp,
                                   object bvector, object ix1, object ix2);

// Replace the subsequence of a byte vector.
KP_EXPORT result<object> rpl_b (interpreter *interp, object bvector,
                                object ix1, object ix2, object rpl);

// Erase the subsequence of a byte vector.
KP_EXPORT result<object> erase_b (interpreter *interp,
                                  object bvector, object ix1, object ix2);

// Insert into a byte vector.
KP_EXPORT result<object> insert_b (interpreter *interp,
                                   object bvector, object ix1, object ins);

// Destructively set an element inside a byte vector.
KP_EXPORT result<object> nput_b (interpreter *interp,
                                 object bvector, object idx, object byte);

// Copy a byte vector.
KP_EXPORT result<object> copy_b (interpreter *interp, object obj, bool deep);

// Iterator interface for a byte vector.
KP_EXPORT result<object> iter_b (interpreter *interp,
                                 object obj, object token, bool adv);

// Write a byte vector to a stream.
KP_EXPORT result<int64_t> write_b (interpreter *interp,
                                   stream *strm, object bvector, io_info& info);

// Serialize a byte vector in a stream.
KP_EXPORT result<int64_t> pack_b (interpreter *interp,
                                  stream *strm, object obj, pack_info& info);

// Deserialize a byte vector from a stream.
KP_EXPORT result<object> unpack_b (interpreter *interp,
                                   stream *strm, pack_info& info, bool save);

// Concatenate byte vectors BV1 and BV2.
KP_EXPORT result<object> add_bb (interpreter *interp, object bv1, object bv2);

// Concatenate ARGC byte vectors from ARGV.
KP_EXPORT result<object> concat_b (interpreter *interp, object *argv, int argc);

// Multiply a byte vector with an integer.
KP_EXPORT result<object> mul_ib (interpreter *interp,
                                 object ix, object bvector);

// Compare byte vectors V1 and V2.
KP_EXPORT int cmp_bb (interpreter *interp, object v1, object v2);

/* Let's take advantage of the fact that both types
 * have the same internal representation. */

inline int cmp_bs (interpreter *interp, object b, object s)
{
  return (cmp_bb (interp, b, s));
}

inline int cmp_ss (interpreter *interp, object s1, object s2)
{
  return (cmp_bb (interp, s1, s2));
}

// Test for byte vector equality.
KP_EXPORT bool eq_bb (interpreter *interp, object v1, object v2);

inline bool eq_bs (interpreter *interp, object b, object s)
{
  return (eq_bb (interp, b, s));
}

inline bool eq_ss (interpreter *interp, object s1, object s2)
{
  return (eq_bb (interp, s1, s2));
}

// Hash the buffer [PTR .. PTR + LEN).
KP_EXPORT uint32_t hashbuf (const void *ptr, uint32_t len);

// Compute the hashcode of a byte vector.
KP_EXPORT uint32_t hash_b (interpreter *interp, object obj);

// Reverse a byte vector.
KP_EXPORT result<object> reverse_b (interpreter *interp, object obj);

// Destructively reverse a byte vector.
KP_EXPORT result<object> nreverse_b (interpreter *interp, object obj);

// Get the last element of a byte vector.
KP_EXPORT result<object> last_b (interpreter *interp, object obj);

// Find a byte or bvector.
KP_EXPORT result<object> find_b (interpreter *interp, object obj,
                                 object key, object start,
                                 object end, object test);

// Create a stream with from byte vector BV.
KP_EXPORT result<stream*> bvstream (interpreter *interp, object bv, int mode);

// Get the byte vector from stream STRM.
KP_EXPORT result<object> bvstream_get (interpreter *interp, stream *strm);

KP_EXPORT unsigned char* bvstream_data (stream *strm, uint32_t& size);

// Init OP for byte vectors.
KP_EXPORT init_op init_bvector;

KP_DECLS_END

#endif
